package com.cqupt.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqupt.exception.BusinessException;
import com.cqupt.mapper.*;
import com.cqupt.model.constant.Constant;
import com.cqupt.model.pojo.*;
import com.cqupt.model.vo.ExampleVO;
import com.cqupt.model.vo.ResultCodeEnum;
import com.cqupt.model.vo.SpeakVO;
import com.cqupt.service.SparkService;
import com.cqupt.service.WordService;
import com.cqupt.utils.AuthContextUtil;
import com.cqupt.utils.MachineTranslationUtil;
import jakarta.annotation.Resource;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;


@Service
public class WordServiceImpl extends ServiceImpl<WordMapper, Word>
        implements WordService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private WordMapper wordMapper;

    @Resource
    private SparkService sparkService;

    @Resource
    private UserWordMapper userWordMapper;

    @Resource
    private ReviewMapper reviewMapper;

    @Resource
    private WordUnknownMapper wordUnknownMapper;


    @Resource
    private WordAccMapper wordAccMapper;

    @Override
    public List<Word> recite(int bookId) {
        SysUser sysUser = AuthContextUtil.get();
        int userId = sysUser.getId();
        String curJson = stringRedisTemplate.opsForValue().get(Constant.CUR_RECITE_WORD + userId + ":" + bookId);
        if (StrUtil.isEmpty(curJson)) {
            String wordJson = stringRedisTemplate.opsForValue().get(userId + ":" + bookId);
            if (!StrUtil.isEmpty(wordJson)) {
                List<Word> wordList = JSON.parseArray(wordJson, Word.class);
                if (wordList.size() >= 10) {
                    List<Word> cur = wordList.stream().limit(10).toList();
                    stringRedisTemplate.opsForValue().set(Constant.CUR_RECITE_WORD + userId + ":" + bookId, JSON.toJSONString(cur));
                    wordList.subList(0, 10).clear();
                    stringRedisTemplate.opsForValue().set(userId + ":" + bookId, JSON.toJSONString(wordList));
                    return cur;
                } else {
                    stringRedisTemplate.delete(userId + ":" + bookId);
                    stringRedisTemplate.opsForValue().set(Constant.CUR_RECITE_WORD + userId + ":" + bookId, JSON.toJSONString(wordList));
                    return wordList;
                }

            } else {
                List<Word> list = wordMapper.getByBookId(bookId);
                if (!Objects.isNull(list)) {
                    List<Word> res = list.stream().limit(10).toList();
                    list.subList(0, 10).clear();
                    stringRedisTemplate.opsForValue().set(userId + ":" + bookId, JSON.toJSONString(list));
                    stringRedisTemplate.opsForValue().set(Constant.CUR_RECITE_WORD + userId + ":" + bookId, JSON.toJSONString(res));
                    return res;
                } else {
                    throw new BusinessException(ResultCodeEnum.DATA_ERROR);
                }
            }
        } else {
            List<Word> curWords = JSON.parseArray(curJson, Word.class);
            return curWords;
        }

    }

    @Override
    public SpeakVO example(String word) {
        String head = "我现在发一个单词给你，请你根据这个单词帮我生成一个英语例句，例句长度适中，一句话即可。下面是我发送的单词:";
        String resText = sparkService.chat(1008611, head + word);
        try {
            String resTranslation = MachineTranslationUtil.translate(resText);
            SpeakVO speakVO = new SpeakVO();
            speakVO.setResText(resText);
            speakVO.setResTranslation(resTranslation);
            return speakVO;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<Word> learn(int bookId,int count) {

        Integer userId = AuthContextUtil.get().getId();
        String json = stringRedisTemplate.opsForValue().get(userId + ":" + bookId);
        if (StrUtil.isEmpty(json)) {
            throw new BusinessException(ResultCodeEnum.DATA_ERROR);
        }
        List<Word> list = JSON.parseArray(json, Word.class);
        if (Objects.isNull(list)) {
            return null;
        } else if (list.size() > count) {
            List<Word> res = list.stream().limit(count).toList();
            return res;
        } else return list;
    }

    @Override
    public List<Word> review(int bookId) {
        Integer userId = AuthContextUtil.get().getId();
//        long time = System.currentTimeMillis();
//        List<Word> review = wordMapper.getReview(userId, bookId, time);
//        stringRedisTemplate.opsForValue().set("review:" + userId + ":" + bookId, JSON.toJSONString(review));

//        String json = stringRedisTemplate.opsForValue().get("review:" + userId + ":" + bookId);
//        if (StrUtil.isEmpty(json)) {
//            throw new BusinessException(ResultCodeEnum.DATA_ERROR);
//        }
//        List<Word> list = JSON.parseArray(json, Word.class);

//        long time = System.currentTimeMillis();
        long time = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
        List<Word> review = wordMapper.getReview(userId, bookId, time);
        if (CollUtil.isEmpty(review)) {
            return null;
        }

        return review;

    }

    @Override
    public Map<String, Integer> index(int bookId) {
        Integer userId = AuthContextUtil.get().getId();
        String learn = stringRedisTemplate.opsForValue().get(userId + ":" + bookId);
        HashMap<String, Integer> map = new HashMap<>();
        if (StrUtil.isEmpty(learn)) {
            map.put("learn", 0);
        } else {
            List<Word> list = JSON.parseArray(learn, Word.class);
            if (Objects.isNull(list)) {
                map.put("learn", 0);
            } else
                map.put("learn", list.size());
        }
        String view = stringRedisTemplate.opsForValue().get("review:" + userId + ":" + bookId);
        if (StrUtil.isEmpty(view)) {
            map.put("view", 0);
        } else {
            List<Word> list = JSON.parseArray(view, Word.class);
            map.put("view", list.size());
        }
        return map;
    }

    @Override
    @Transactional
    public void known(int bookId, int wordId) {
        Integer userId = AuthContextUtil.get().getId();

        LambdaQueryWrapper<Review> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Review::getUserId, userId);
        wrapper.eq(Review::getBookId, bookId);
        wrapper.eq(Review::getWordId, wordId);
        Review one = reviewMapper.selectOne(wrapper);
        if (Objects.isNull(one)) {
            Review review = new Review();
            review.setUserId(userId);
            review.setWordId(wordId);
            review.setBookId(bookId);
            LocalDateTime now = LocalDateTime.now();
            review.setLearnDate(now.toEpochSecond(ZoneOffset.UTC));
            review.setReviewDate(now.plusDays(1).toEpochSecond(ZoneOffset.UTC));
            review.setCorrectTimes(1);
            reviewMapper.insert(review);
        } else {
            Integer correctTimes = one.getCorrectTimes();
            one.setCorrectTimes(++correctTimes);
            LocalDateTime now = LocalDateTime.now();
            one.setLearnDate(now.toEpochSecond(ZoneOffset.UTC));
            if (correctTimes == 1) {
                one.setReviewDate(now.plusDays(1).toEpochSecond(ZoneOffset.UTC));
            } else if (correctTimes == 2) {
                one.setReviewDate(now.plusDays(2).toEpochSecond(ZoneOffset.UTC));
            } else if (correctTimes == 3) {
                one.setReviewDate(now.plusDays(4).toEpochSecond(ZoneOffset.UTC));
            } else if (correctTimes == 4) {
                one.setReviewDate(now.plusDays(7).toEpochSecond(ZoneOffset.UTC));
            } else if (correctTimes == 5) {
                one.setReviewDate(now.plusDays(15).toEpochSecond(ZoneOffset.UTC));
            } else if (correctTimes >= 6) {
                one.setReviewDate(now.plusDays(30).toEpochSecond(ZoneOffset.UTC));
            }
            reviewMapper.updateById(one);

        }

        LambdaQueryWrapper<UserWord> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(UserWord::getUserId, userId);
        wrapper2.eq(UserWord::getWordId, wordId);
        wrapper2.eq(UserWord::getBookId, bookId);
        UserWord userWord = userWordMapper.selectOne(wrapper2);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        String formatDate = sdf.format(date);
        if (ObjectUtil.isNull(userWord)) {
            UserWord userWord1 = new UserWord();
            userWord1.setUserId(userId);
            userWord1.setBookId(bookId);
            userWord1.setWordId(wordId);
            userWord1.setDate(formatDate);
            userWordMapper.insert(userWord1);
        } else {
            userWord.setDate(formatDate);
            userWordMapper.updateById(userWord);
        }


        LambdaQueryWrapper<WordUnknown> wrapper3 = new LambdaQueryWrapper<>();
        wrapper3.eq(WordUnknown::getUserId, userId);
        wrapper3.eq(WordUnknown::getWordId, wordId);
        WordUnknown wordUnknown = wordUnknownMapper.selectOne(wrapper3);
        if (!ObjectUtil.isNull(wordUnknown)) {
            wordUnknown.setIsLearn(1);
            wordUnknownMapper.updateById(wordUnknown);
        }

        LambdaQueryWrapper<WordAcc> wrapper4 = new LambdaQueryWrapper<>();
        wrapper4.eq(WordAcc::getUserId, userId);
        WordAcc wordAcc = wordAccMapper.selectOne(wrapper4);
        if (ObjectUtil.isNull(wordAcc)) {
            WordAcc wordAcc1 = new WordAcc();
            wordAcc1.setUserId(userId);
            wordAcc1.setTotalCount(1);
            wordAcc1.setRightCount(1);
            wordAccMapper.insert(wordAcc1);
        } else {
            wordAcc.setTotalCount(wordAcc.getTotalCount() + 1);
            wordAcc.setRightCount(wordAcc.getRightCount() + 1);
            wordAccMapper.updateById(wordAcc);
        }
    }

    @Override
    @Transactional
    public void forget(int bookId, int wordId) {
        Integer userId = AuthContextUtil.get().getId();
        LambdaQueryWrapper<Review> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Review::getUserId, userId);
        wrapper.eq(Review::getBookId, bookId);
        wrapper.eq(Review::getWordId, wordId);
        Review one = reviewMapper.selectOne(wrapper);
        if (ObjectUtil.isNull(one)) {
            Review review = new Review();
            review.setUserId(userId);
            review.setWordId(wordId);
            review.setBookId(bookId);
            LocalDateTime now = LocalDateTime.now();
            review.setLearnDate(now.toEpochSecond(ZoneOffset.UTC));
            review.setReviewDate(now.toEpochSecond(ZoneOffset.UTC));
            review.setCorrectTimes(0);
            reviewMapper.insert(review);
        } else {
            one.setCorrectTimes(0);
            LocalDateTime now = LocalDateTime.now();
            one.setLearnDate(now.toEpochSecond(ZoneOffset.UTC));
            one.setReviewDate(now.toEpochSecond(ZoneOffset.UTC));
            reviewMapper.updateById(one);
        }

        LambdaQueryWrapper<UserWord> wrapper2 = new LambdaQueryWrapper<>();
        wrapper2.eq(UserWord::getUserId, userId);
        wrapper2.eq(UserWord::getWordId, wordId);
        wrapper2.eq(UserWord::getBookId, bookId);
        UserWord userWord = userWordMapper.selectOne(wrapper2);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        String formatDate = sdf.format(date);
        if (ObjectUtil.isNull(userWord)) {
            UserWord userWord1 = new UserWord();
            userWord1.setUserId(userId);
            userWord1.setBookId(bookId);
            userWord1.setWordId(wordId);
            userWord1.setDate(formatDate);
            userWordMapper.insert(userWord1);
        } else {
            userWord.setDate(formatDate);
            userWordMapper.updateById(userWord);
        }

        LambdaQueryWrapper<WordAcc> wrapper4 = new LambdaQueryWrapper<>();
        wrapper4.eq(WordAcc::getUserId, userId);
        WordAcc wordAcc = wordAccMapper.selectOne(wrapper4);
        if (ObjectUtil.isNull(wordAcc)) {
            WordAcc wordAcc1 = new WordAcc();
            wordAcc1.setUserId(userId);
            wordAcc1.setTotalCount(1);
            wordAcc1.setRightCount(0);
            wordAccMapper.insert(wordAcc1);
        } else {
            wordAcc.setTotalCount(wordAcc.getTotalCount() + 1);
            wordAccMapper.updateById(wordAcc);
        }


    }

    @Override
    public List<Word> allWord(int bookId) {
        return wordMapper.getByBookId(bookId);
    }

    @Override
    public List<Word> getWord(int bookId, String word) {

        return wordMapper.getWord(bookId, word);
    }

    @Override
    public List<ExampleVO> example2(String word) {
        // 1、创建HttpClient实例
        CloseableHttpClient client = HttpClients.createDefault();
        // 2、创建GET请求方法实例
        HttpGet httpGet = new HttpGet("https://api.dictionaryapi.dev/api/v2/entries/en/" + word);
        // 3、调用HttpClient实例执行GET实例，返回response
        try {
            // 4. 从response获取应答信息，判断是否访问成功
            CloseableHttpResponse response = client.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                // 5. 打印结果
                String json = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println(json);
                JSONArray jsonArray = JSON.parseArray(json);
                ArrayList<ExampleVO> list = new ArrayList<>();
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    JSONArray meanings = jsonObject.getJSONArray("meanings");
                    for (int j = 0; j < meanings.size(); j++) {
                        JSONArray definitions = meanings.getJSONObject(j).getJSONArray("definitions");
                        for (int k = 0; k < definitions.size(); k++) {
                            if (definitions.getJSONObject(k).containsKey("example")) {
                                String example = definitions.getJSONObject(k).getString("example");
//                                String translation = MachineTranslationUtil.translate(example);
                                ExampleVO exampleVO = new ExampleVO();
                                exampleVO.setExample(example);
//                                exampleVO.setTranslation(translation);
                                list.add(exampleVO);
                            }
                        }
                    }
                }
                return list;
            } else {
                System.out.println("请求失败，状态码：" + response.getStatusLine().getStatusCode());
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                // 6、释放资源
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;


    }

    @Override
    public List<Word> getByPage(int bookId, int pageNum) {
        int end = 20 * (pageNum - 1);
        return wordMapper.getByPage(bookId, end);
    }

    @Override
    public Integer queryByWord(String word) {
        Integer userId = AuthContextUtil.get().getId();
        LambdaQueryWrapper<Word> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Word::getWord, word);
        List<Word> list = wordMapper.selectList(wrapper);
        if (ObjectUtil.isEmpty(list)) {
            return -1;
        }
        for (Word ele : list) {
            Integer wordId = ele.getId();
            LambdaQueryWrapper<WordUnknown> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.eq(WordUnknown::getUserId, userId);
            wrapper1.eq(WordUnknown::getWordId, wordId);
            WordUnknown one = wordUnknownMapper.selectOne(wrapper1);
            if (ObjectUtil.isNotNull(one)) {
                return wordId;
            }
        }
        return -1;
    }


}
